#ifndef __POLL_SVR_H__
#define __POLL_SVR_H__

#include <iostream>
#include <poll.h>
#include <string>
#include "Sock.hpp"

#define FD_NONE -1

using namespace std;

class PollServer
{
public:
    static const int nfds = 100; // 最大文件描述符个数
public:
    // 构造：绑定并监听套接字
    PollServer(const uint16_t port = 8080): _port(port), _nfds(nfds)
    {
        // 绑定监听
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        logMessage(NORMAL, "%s", "create base socket success.");

        // 初始化pollfd
        _fds = new struct pollfd[_nfds];
        for(int i = 0; i < _nfds; ++i)
        {
            _fds[i].fd = FD_NONE;
            _fds[i].events = 0;
            _fds[i].revents = 0;
        }
        _fds[0].fd = _listensock;
        _fds[0].events = POLLIN;

        _timeout = 1000;
    }

    ~PollServer()
    {
        // 关闭套接字
        if(_listensock != FD_NONE)
            close(_listensock);
        // 释放资源
        if(_fds) delete []_fds;
    }

    void Start()
    {
        DebugPrint();
        while(true)
        {
            int n = poll(_fds, _nfds, _timeout); // 等待事件
            switch(n)
            {
            case 0: // 超时
                logMessage(DEBUG, "%s", "time out...");
                break;
            case -1:
                logMessage(WARNING, "poll error | %d : %s", errno, strerror(errno));
            default:
                logMessage(NORMAL, "poll success: get a new link event.");

                HandlerEvent();
                break;
            }
        }
    }
private:
    // 处理事件
    void HandlerEvent()
    {
        for(int i = 0; i < _nfds; ++i)
        {
            int& fd = _fds[i].fd;
            // 去掉无效 fd
            if(fd == FD_NONE) continue;
            if(_fds[i].revents & POLLIN)
            {
                // 此时的 fd 读事件就绪
                if(fd == _listensock) Accepter(); // 建立连接
                else Recver(i); // 接收数据
            }
        }
    }

    void Accepter()
    {
        string clientIp;
        uint16_t clientPort;
        int sock = Sock::Accept(_listensock, &clientIp, &clientPort);
        if(sock < 0){
            logMessage(WARNING, "accept error | %d : %s", errno, strerror(errno));
            return;
        }

        logMessage(NORMAL, "accept a new link from %s : %d", clientIp.c_str(), clientPort);
        // 添加fd
        int pos = 1;
        for(; pos < _nfds; ++pos)
            if(_fds[pos].fd == FD_NONE) break;
        
        // 文件描述符存满了，扩容
        if(pos == _nfds) {
            logMessage(WARNING, "%s:%d", "poll server already full, close: %d", clientIp.c_str(), clientPort, sock);
            close(sock);
        } else {
            _fds[pos].fd = sock;
            _fds[pos].events = POLLIN;
            // _fds[pos].revents = 0; // 已经初始化过
        }
    }

    void Recver(int pos)
    {
        // 此时读事件就绪，进行读取：
        pollfd& pfd = _fds[pos];
        logMessage(DEBUG, "message in, get IO event: %d", pfd);

        char buffer[1024];
        int n = recv(pfd.fd, buffer, sizeof(buffer) - 1, 0);
        if(n > 0){ // 读取成功
            buffer[n] = 0;
            logMessage(NORMAL, "recv success, client[%d]# %s", pfd.fd, buffer);
        } else if (n == 0) { // 对端关闭
            logMessage(DEBUG, "client quit[%d], me too.", pfd.fd, buffer);
            // 关闭该fd
            close(pfd.fd);
            // poll 不必再关心该fd
            pfd.fd = FD_NONE;
            pfd.events = 0;
        } else { // 读取失败
            logMessage(WARNING, "recv error[%d] | %d : %s", pfd.fd, errno, strerror(errno));
            // 关闭fd
            close(pfd.fd);
            // poll不必再关心该fd
            pfd.fd = FD_NONE;
            pfd.events = 0;
        }   
    }

    // 打印连接信息
    void DebugPrint()
    {
        cout << "_fds[].fd: ";
        for(int i = 0; i < _nfds; ++i)
        {
            if(_fds[i].fd != FD_NONE)
                cout << _fds[i].fd << " ";
        }
        cout << endl;
    }

    // _________________________________________________ //

private:
    uint16_t _port; // 端口号
    int _listensock; // 监听套接字
    struct pollfd* _fds; // pollfd数组
    int _nfds; // 设置的最大fd数量
    int _timeout; // 设置超时时间（阻塞等待）
};

#endif